home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / ai_chat.c next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  32.4 KB  |  1,142 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3.  
  4. /*****************************************************************************
  5.  * name:        ai_chat.c
  6.  *
  7.  * desc:        Quake3 bot AI
  8.  *
  9.  * $Archive: /source/code/game/ai_chat.c $
  10.  * $Author: Raduffy $ 
  11.  * $Revision: 5 $
  12.  * $Modtime: 1/14/00 5:27p $
  13.  * $Date: 1/14/00 5:35p $
  14.  *
  15.  *****************************************************************************/
  16.  
  17. #include "g_local.h"
  18. #include "botlib.h"
  19. #include "be_aas.h"
  20. #include "be_ea.h"
  21. #include "be_ai_char.h"
  22. #include "be_ai_chat.h"
  23. #include "be_ai_gen.h"
  24. #include "be_ai_goal.h"
  25. #include "be_ai_move.h"
  26. #include "be_ai_weap.h"
  27. //
  28. #include "ai_main.h"
  29. #include "ai_dmq3.h"
  30. #include "ai_chat.h"
  31. #include "ai_cmd.h"
  32. #include "ai_dmnet.h"
  33. //
  34. #include "chars.h"                //characteristics
  35. #include "inv.h"                //indexes into the inventory
  36. #include "syn.h"                //synonyms
  37. #include "match.h"                //string matching types and vars
  38.  
  39.  
  40. /*
  41. ==================
  42. BotNumActivePlayers
  43. ==================
  44. */
  45. int BotNumActivePlayers(void) {
  46.     int i, num;
  47.     char buf[MAX_INFO_STRING];
  48.     static int maxclients;
  49.  
  50.     if (!maxclients)
  51.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  52.  
  53.     num = 0;
  54.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  55.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  56.         //if no config string or no name
  57.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  58.         //skip spectators
  59.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  60.         //
  61.         num++;
  62.     }
  63.     return num;
  64. }
  65.  
  66. /*
  67. ==================
  68. BotIsFirstInRankings
  69. ==================
  70. */
  71. int BotIsFirstInRankings(bot_state_t *bs) {
  72.     int i, score;
  73.     char buf[MAX_INFO_STRING];
  74.     static int maxclients;
  75.     playerState_t ps;
  76.  
  77.     if (!maxclients)
  78.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  79.  
  80.     score = bs->cur_ps.persistant[PERS_SCORE];
  81.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  82.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  83.         //if no config string or no name
  84.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  85.         //skip spectators
  86.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  87.         //
  88.         BotAI_GetClientState(i, &ps);
  89.         if (score < ps.persistant[PERS_SCORE]) return qfalse;
  90.     }
  91.     return qtrue;
  92. }
  93.  
  94. /*
  95. ==================
  96. BotIsLastInRankings
  97. ==================
  98. */
  99. int BotIsLastInRankings(bot_state_t *bs) {
  100.     int i, score;
  101.     char buf[MAX_INFO_STRING];
  102.     static int maxclients;
  103.     playerState_t ps;
  104.  
  105.     if (!maxclients)
  106.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  107.  
  108.     score = bs->cur_ps.persistant[PERS_SCORE];
  109.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  110.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  111.         //if no config string or no name
  112.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  113.         //skip spectators
  114.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  115.         //
  116.         BotAI_GetClientState(i, &ps);
  117.         if (score > ps.persistant[PERS_SCORE]) return qfalse;
  118.     }
  119.     return qtrue;
  120. }
  121.  
  122. /*
  123. ==================
  124. BotFirstClientInRankings
  125. ==================
  126. */
  127. char *BotFirstClientInRankings(void) {
  128.     int i, bestscore, bestclient;
  129.     char buf[MAX_INFO_STRING];
  130.     static char name[32];
  131.     static int maxclients;
  132.     playerState_t ps;
  133.  
  134.     if (!maxclients)
  135.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  136.  
  137.     bestscore = -999999;
  138.     bestclient = 0;
  139.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  140.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  141.         //if no config string or no name
  142.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  143.         //skip spectators
  144.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  145.         //
  146.         BotAI_GetClientState(i, &ps);
  147.         if (ps.persistant[PERS_SCORE] > bestscore) {
  148.             bestscore = ps.persistant[PERS_SCORE];
  149.             bestclient = i;
  150.         }
  151.     }
  152.     EasyClientName(bestclient, name, 32);
  153.     return name;
  154. }
  155.  
  156. /*
  157. ==================
  158. BotLastClientInRankings
  159. ==================
  160. */
  161. char *BotLastClientInRankings(void) {
  162.     int i, worstscore, bestclient;
  163.     char buf[MAX_INFO_STRING];
  164.     static char name[32];
  165.     static int maxclients;
  166.     playerState_t ps;
  167.  
  168.     if (!maxclients)
  169.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  170.  
  171.     worstscore = 999999;
  172.     bestclient = 0;
  173.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  174.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  175.         //if no config string or no name
  176.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  177.         //skip spectators
  178.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  179.         //
  180.         BotAI_GetClientState(i, &ps);
  181.         if (ps.persistant[PERS_SCORE] < worstscore) {
  182.             worstscore = ps.persistant[PERS_SCORE];
  183.             bestclient = i;
  184.         }
  185.     }
  186.     EasyClientName(bestclient, name, 32);
  187.     return name;
  188. }
  189.  
  190. /*
  191. ==================
  192. BotRandomOpponentName
  193. ==================
  194. */
  195. char *BotRandomOpponentName(bot_state_t *bs) {
  196.     int i, count;
  197.     char buf[MAX_INFO_STRING];
  198.     int opponents[MAX_CLIENTS], numopponents;
  199.     static int maxclients;
  200.     static char name[32];
  201.  
  202.     if (!maxclients)
  203.         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
  204.  
  205.     numopponents = 0;
  206.     opponents[0] = 0;
  207.     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  208.         if (i == bs->client) continue;
  209.         //
  210.         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  211.         //if no config string or no name
  212.         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  213.         //skip spectators
  214.         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
  215.         //skip team mates
  216.         if (BotSameTeam(bs, i)) continue;
  217.         //
  218.         opponents[numopponents] = i;
  219.         numopponents++;
  220.     }
  221.     count = random() * numopponents;
  222.     for (i = 0; i < numopponents; i++) {
  223.         count--;
  224.         if (count <= 0) {
  225.             EasyClientName(opponents[i], name, sizeof(name));
  226.             return name;
  227.         }
  228.     }
  229.     EasyClientName(opponents[0], name, sizeof(name));
  230.     return name;
  231. }
  232.  
  233. /*
  234. ==================
  235. BotMapTitle
  236. ==================
  237. */
  238.  
  239. char *BotMapTitle(void) {
  240.     char info[1024];
  241.     static char mapname[128];
  242.  
  243.     trap_GetServerinfo(info, sizeof(info));
  244.  
  245.     strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
  246.     mapname[sizeof(mapname)-1] = '\0';
  247.  
  248.     return mapname;
  249. }
  250.  
  251.  
  252. /*
  253. ==================
  254. BotWeaponNameForMeansOfDeath
  255. ==================
  256. */
  257.  
  258. char *BotWeaponNameForMeansOfDeath(int mod) {
  259.     switch(mod) {
  260.         case MOD_SHOTGUN: return "Shotgun";
  261.         case MOD_GAUNTLET: return "Gauntlet";
  262.         case MOD_MACHINEGUN: return "Machinegun";
  263.         case MOD_GRENADE:
  264.         case MOD_GRENADE_SPLASH: return "Grenade Launcher";
  265.         case MOD_ROCKET:
  266.         case MOD_ROCKET_SPLASH: return "Rocket Launcher";
  267.         case MOD_PLASMA:
  268.         case MOD_PLASMA_SPLASH: return "Plasmagun";
  269.         case MOD_RAILGUN: return "Railgun";
  270.         case MOD_LIGHTNING: return "Lightning Gun";
  271.         case MOD_BFG:
  272.         case MOD_BFG_SPLASH: return "BFG10K";
  273.         case MOD_GRAPPLE: return "Grapple";
  274.         default: return "[unknown weapon]";
  275.     }
  276. }
  277.  
  278. /*
  279. ==================
  280. BotRandomWeaponName
  281. ==================
  282. */
  283. char *BotRandomWeaponName(void) {
  284.     int rnd;
  285.  
  286.     rnd = random() * 8.9;
  287.     switch(rnd) {
  288.         case 0: return "Gauntlet";
  289.         case 1: return "Shotgun";
  290.         case 2: return "Machinegun";
  291.         case 3: return "Grenade Launcher";
  292.         case 4: return "Rocket Launcher";
  293.         case 5: return "Plasmagun";
  294.         case 6: return "Railgun";
  295.         case 7: return "Lightning Gun";
  296.         default: return "BFG10K";
  297.     }
  298. }
  299.  
  300. /*
  301. ==================
  302. BotVisibleEnemies
  303. ==================
  304. */
  305. int BotVisibleEnemies(bot_state_t *bs) {
  306.     float vis, dist;
  307.     int i;
  308.     vec3_t dir;
  309.     aas_entityinfo_t entinfo;
  310.  
  311.     for (i = 0; i < MAX_CLIENTS; i++) {
  312.  
  313.         if (i == bs->client) continue;
  314.         //
  315.         BotEntityInfo(i, &entinfo);
  316.         //
  317.         if (!entinfo.valid) continue;
  318.         //if the enemy isn't dead and the enemy isn't the bot self
  319.         if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
  320.         //if the enemy is invisible and not shooting
  321.         if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
  322.             continue;
  323.         }
  324.         //calculate the distance towards the enemy
  325.         VectorSubtract(entinfo.origin, bs->origin, dir);
  326.         dist = VectorLength(dir);
  327.         //if on the same team
  328.         if (BotSameTeam(bs, i)) continue;
  329.         //check if the enemy is visible
  330.         vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
  331.         if (vis > 0) return qtrue;
  332.     }
  333.     return qfalse;
  334. }
  335.  
  336. /*
  337. ==================
  338. BotValidChatPosition
  339. ==================
  340. */
  341. int BotValidChatPosition(bot_state_t *bs) {
  342.     vec3_t point, start, end, mins, maxs;
  343.     bsp_trace_t trace;
  344.  
  345.     //if the bot is dead all positions are valid
  346.     if (BotIsDead(bs)) return qtrue;
  347.     //never start chatting with a powerup
  348.     if (bs->inventory[INVENTORY_QUAD] ||
  349.         bs->inventory[INVENTORY_HASTE] ||
  350.         bs->inventory[INVENTORY_INVISIBILITY] ||
  351.         bs->inventory[INVENTORY_REGEN] ||
  352.         bs->inventory[INVENTORY_FLIGHT]) return qfalse;
  353.     //must be on the ground
  354.     //if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;
  355.     //do not chat if in lava or slime
  356.     VectorCopy(bs->origin, point);
  357.     point[2] -= 24;
  358.     if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
  359.     //do not chat if under water
  360.     VectorCopy(bs->origin, point);
  361.     point[2] += 32;
  362.     if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
  363.     //must be standing on the world entity
  364.     VectorCopy(bs->origin, start);
  365.     VectorCopy(bs->origin, end);
  366.     start[2] += 1;
  367.     end[2] -= 10;
  368.     trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
  369.     BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
  370.     if (trace.ent != ENTITYNUM_WORLD) return qfalse;
  371.     //the bot is in a position where it can chat
  372.     return qtrue;
  373. }
  374.  
  375. /*
  376. ==================
  377. BotChat_EnterGame
  378. ==================
  379. */
  380. int BotChat_EnterGame(bot_state_t *bs) {
  381.     char name[32];
  382.     float rnd;
  383.  
  384.     if (bot_nochat.integer) return qfalse;
  385.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  386.     //don't chat in teamplay
  387.     if (TeamPlayIsOn()) return qfalse;
  388.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
  389.     if (!bot_fastchat.integer) {
  390.         if (random() > rnd) return qfalse;
  391.     }
  392.     if (BotNumActivePlayers() <= 1) return qfalse;
  393.     if (!BotValidChatPosition(bs)) return qfalse;
  394.     BotAI_BotInitialChat(bs, "game_enter",
  395.                 EasyClientName(bs->client, name, 32),    // 0
  396.                 BotRandomOpponentName(bs),                // 1
  397.                 "[invalid var]",                        // 2
  398.                 "[invalid var]",                        // 3
  399.                 BotMapTitle(),                            // 4
  400.                 NULL);
  401.     bs->lastchat_time = trap_AAS_Time();
  402.     bs->chatto = CHAT_ALL;
  403.     return qtrue;
  404. }
  405.  
  406. /*
  407. ==================
  408. BotChat_ExitGame
  409. ==================
  410. */
  411. int BotChat_ExitGame(bot_state_t *bs) {
  412.     char name[32];
  413.     float rnd;
  414.  
  415.     if (bot_nochat.integer) return qfalse;
  416.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  417.     //don't chat in teamplay
  418.     if (TeamPlayIsOn()) return qfalse;
  419.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
  420.     if (!bot_fastchat.integer) {
  421.         if (random() > rnd) return qfalse;
  422.     }
  423.     if (BotNumActivePlayers() <= 1) return qfalse;
  424.     //
  425.     BotAI_BotInitialChat(bs, "game_exit",
  426.                 EasyClientName(bs->client, name, 32),    // 0
  427.                 BotRandomOpponentName(bs),                // 1
  428.                 "[invalid var]",                        // 2
  429.                 "[invalid var]",                        // 3
  430.                 BotMapTitle(),                            // 4
  431.                 NULL);
  432.     bs->lastchat_time = trap_AAS_Time();
  433.     bs->chatto = CHAT_ALL;
  434.     return qtrue;
  435. }
  436.  
  437. /*
  438. ==================
  439. BotChat_StartLevel
  440. ==================
  441. */
  442. int BotChat_StartLevel(bot_state_t *bs) {
  443.     char name[32];
  444.     float rnd;
  445.  
  446.     if (bot_nochat.integer) return qfalse;
  447.     if (BotIsObserver(bs)) return qfalse;
  448.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  449.     //don't chat in teamplay
  450.     if (TeamPlayIsOn()) return qfalse;
  451.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
  452.     if (!bot_fastchat.integer) {
  453.         if (random() > rnd) return qfalse;
  454.     }
  455.     if (BotNumActivePlayers() <= 1) return qfalse;
  456.     BotAI_BotInitialChat(bs, "level_start",
  457.                 EasyClientName(bs->client, name, 32),    // 0
  458.                 NULL);
  459.     bs->lastchat_time = trap_AAS_Time();
  460.     bs->chatto = CHAT_ALL;
  461.     return qtrue;
  462. }
  463.  
  464. /*
  465. ==================
  466. BotChat_EndLevel
  467. ==================
  468. */
  469. int BotChat_EndLevel(bot_state_t *bs) {
  470.     char name[32];
  471.     float rnd;
  472.  
  473.     if (bot_nochat.integer) return qfalse;
  474.     if (BotIsObserver(bs)) return qfalse;
  475.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  476.     //don't chat in teamplay
  477.     if (TeamPlayIsOn()) return qfalse;
  478.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
  479.     if (!bot_fastchat.integer) {
  480.         if (random() > rnd) return qfalse;
  481.     }
  482.     if (BotNumActivePlayers() <= 1) return qfalse;
  483.     //
  484.     if (BotIsFirstInRankings(bs)) {
  485.         BotAI_BotInitialChat(bs, "level_end_victory",
  486.                 EasyClientName(bs->client, name, 32),    // 0
  487.                 BotRandomOpponentName(bs),                // 1
  488.                 "[invalid var]",                        // 2
  489.                 BotLastClientInRankings(),                // 3
  490.                 BotMapTitle(),                            // 4
  491.                 NULL);
  492.     }
  493.     else if (BotIsLastInRankings(bs)) {
  494.         BotAI_BotInitialChat(bs, "level_end_lose",
  495.                 EasyClientName(bs->client, name, 32),    // 0
  496.                 BotRandomOpponentName(bs),                // 1
  497.                 BotFirstClientInRankings(),                // 2
  498.                 "[invalid var]",                        // 3
  499.                 BotMapTitle(),                            // 4
  500.                 NULL);
  501.     }
  502.     else {
  503.         BotAI_BotInitialChat(bs, "level_end",
  504.                 EasyClientName(bs->client, name, 32),    // 0
  505.                 BotRandomOpponentName(bs),                // 1
  506.                 BotFirstClientInRankings(),                // 2
  507.                 BotLastClientInRankings(),                // 3
  508.                 BotMapTitle(),                            // 4
  509.                 NULL);
  510.     }
  511.     bs->lastchat_time = trap_AAS_Time();
  512.     bs->chatto = CHAT_ALL;
  513.     return qtrue;
  514. }
  515.  
  516. /*
  517. ==================
  518. BotChat_Death
  519. ==================
  520. */
  521. int BotChat_Death(bot_state_t *bs) {
  522.     char name[32];
  523.     float rnd;
  524.  
  525.     if (bot_nochat.integer) return qfalse;
  526.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  527.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
  528.     //if fast chatting is off
  529.     if (!bot_fastchat.integer) {
  530.         if (random() > rnd) return qfalse;
  531.     }
  532.     if (BotNumActivePlayers() <= 1) return qfalse;
  533.     //
  534.     if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
  535.         EasyClientName(bs->lastkilledby, name, 32);
  536.     else
  537.         strcpy(name, "[world]");
  538.     //
  539.     if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
  540.         if (bs->lastkilledby == bs->client) return qfalse;
  541.         BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
  542.         bs->chatto = CHAT_TEAM;
  543.     }
  544.     else
  545.     {
  546.         //don't chat in teamplay
  547.         if (TeamPlayIsOn()) return qfalse;
  548.         //
  549.         if (bs->botdeathtype == MOD_WATER)
  550.             BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
  551.         else if (bs->botdeathtype == MOD_SLIME)
  552.             BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
  553.         else if (bs->botdeathtype == MOD_LAVA)
  554.             BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
  555.         else if (bs->botdeathtype == MOD_FALLING)
  556.             BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
  557.         else if (bs->botsuicide || //all other suicides by own weapon
  558.                 bs->botdeathtype == MOD_CRUSH ||
  559.                 bs->botdeathtype == MOD_SUICIDE ||
  560.                 bs->botdeathtype == MOD_TARGET_LASER ||
  561.                 bs->botdeathtype == MOD_TRIGGER_HURT ||
  562.                 bs->botdeathtype == MOD_UNKNOWN)
  563.             BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
  564.         else if (bs->botdeathtype == MOD_TELEFRAG)
  565.             BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
  566.         else {
  567.             if ((bs->botdeathtype == MOD_GAUNTLET ||
  568.                 bs->botdeathtype == MOD_RAILGUN ||
  569.                 bs->botdeathtype == MOD_BFG ||
  570.                 bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
  571.  
  572.                 if (bs->botdeathtype == MOD_GAUNTLET)
  573.                     BotAI_BotInitialChat(bs, "death_gauntlet",
  574.                             name,                                                // 0
  575.                             BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  576.                             NULL);
  577.                 else if (bs->botdeathtype == MOD_RAILGUN)
  578.                     BotAI_BotInitialChat(bs, "death_rail",
  579.                             name,                                                // 0
  580.                             BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  581.                             NULL);
  582.                 else
  583.                     BotAI_BotInitialChat(bs, "death_bfg",
  584.                             name,                                                // 0
  585.                             BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  586.                             NULL);
  587.             }
  588.             //choose between insult and praise
  589.             else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
  590.                 BotAI_BotInitialChat(bs, "death_insult",
  591.                             name,                                                // 0
  592.                             BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  593.                             NULL);
  594.             }
  595.             else {
  596.                 BotAI_BotInitialChat(bs, "death_praise",
  597.                             name,                                                // 0
  598.                             BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  599.                             NULL);
  600.             }
  601.         }
  602.         bs->chatto = CHAT_ALL;
  603.     }
  604.     bs->lastchat_time = trap_AAS_Time();
  605.     return qtrue;
  606. }
  607.  
  608. /*
  609. ==================
  610. BotChat_Kill
  611. ==================
  612. */
  613. int BotChat_Kill(bot_state_t *bs) {
  614.     char name[32];
  615.     float rnd;
  616.  
  617.     if (bot_nochat.integer) return qfalse;
  618.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  619.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
  620.     //if fast chat is off
  621.     if (!bot_fastchat.integer) {
  622.         if (random() > rnd) return qfalse;
  623.     }
  624.     if (bs->lastkilledplayer == bs->client) return qfalse;
  625.     if (BotNumActivePlayers() <= 1) return qfalse;
  626.     if (!BotValidChatPosition(bs)) return qfalse;
  627.     //
  628.     if (BotVisibleEnemies(bs)) return qfalse;
  629.     //
  630.     EasyClientName(bs->lastkilledplayer, name, 32);
  631.     //
  632.     bs->chatto = CHAT_ALL;
  633.     if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
  634.         BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
  635.         bs->chatto = CHAT_TEAM;
  636.     }
  637.     else
  638.     {
  639.         //don't chat in teamplay
  640.         if (TeamPlayIsOn()) return qfalse;
  641.         //
  642.         if (bs->enemydeathtype == MOD_GAUNTLET) {
  643.             BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
  644.         }
  645.         else if (bs->enemydeathtype == MOD_RAILGUN) {
  646.             BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
  647.         }
  648.         else if (bs->enemydeathtype == MOD_TELEFRAG) {
  649.             BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
  650.         }
  651.         //choose between insult and praise
  652.         else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
  653.             BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
  654.         }
  655.         else {
  656.             BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
  657.         }
  658.     }
  659.     bs->lastchat_time = trap_AAS_Time();
  660.     return qtrue;
  661. }
  662.  
  663. /*
  664. ==================
  665. BotChat_EnemySuicide
  666. ==================
  667. */
  668. int BotChat_EnemySuicide(bot_state_t *bs) {
  669.     char name[32];
  670.     float rnd;
  671.  
  672.     if (bot_nochat.integer) return qfalse;
  673.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  674.     if (BotNumActivePlayers() <= 1) return qfalse;
  675.     //
  676.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
  677.     //don't chat in teamplay
  678.     if (TeamPlayIsOn()) return qfalse;
  679.     //if fast chat is off
  680.     if (!bot_fastchat.integer) {
  681.         if (random() > rnd) return qfalse;
  682.     }
  683.     if (!BotValidChatPosition(bs)) return qfalse;
  684.     //
  685.     if (BotVisibleEnemies(bs)) return qfalse;
  686.     //
  687.     if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
  688.     else strcpy(name, "");
  689.     BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
  690.     bs->lastchat_time = trap_AAS_Time();
  691.     bs->chatto = CHAT_ALL;
  692.     return qtrue;
  693. }
  694.  
  695. /*
  696. ==================
  697. BotChat_HitTalking
  698. ==================
  699. */
  700. int BotChat_HitTalking(bot_state_t *bs) {
  701.     char name[32], *weap;
  702.     int lasthurt_client;
  703.     float rnd;
  704.  
  705.     if (bot_nochat.integer) return qfalse;
  706.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  707.     if (BotNumActivePlayers() <= 1) return qfalse;
  708.     lasthurt_client = g_entities[bs->client].client->lasthurt_client;
  709.     if (!lasthurt_client) return qfalse;
  710.     if (lasthurt_client == bs->client) return qfalse;
  711.     //
  712.     if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
  713.     //
  714.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
  715.     //don't chat in teamplay
  716.     if (TeamPlayIsOn()) return qfalse;
  717.     //if fast chat is off
  718.     if (!bot_fastchat.integer) {
  719.         if (random() > rnd * 0.5) return qfalse;
  720.     }
  721.     if (!BotValidChatPosition(bs)) return qfalse;
  722.     //
  723.     ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
  724.     weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
  725.     //
  726.     BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
  727.     bs->lastchat_time = trap_AAS_Time();
  728.     bs->chatto = CHAT_ALL;
  729.     return qtrue;
  730. }
  731.  
  732. /*
  733. ==================
  734. BotChat_HitNoDeath
  735. ==================
  736. */
  737. int BotChat_HitNoDeath(bot_state_t *bs) {
  738.     char name[32], *weap;
  739.     float rnd;
  740.     int lasthurt_client;
  741.     aas_entityinfo_t entinfo;
  742.  
  743.     lasthurt_client = g_entities[bs->client].client->lasthurt_client;
  744.     if (!lasthurt_client) return qfalse;
  745.     if (lasthurt_client == bs->client) return qfalse;
  746.     //
  747.     if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
  748.     //
  749.     if (bot_nochat.integer) return qfalse;
  750.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  751.     if (BotNumActivePlayers() <= 1) return qfalse;
  752.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
  753.     //don't chat in teamplay
  754.     if (TeamPlayIsOn()) return qfalse;
  755.     //if fast chat is off
  756.     if (!bot_fastchat.integer) {
  757.         if (random() > rnd * 0.5) return qfalse;
  758.     }
  759.     if (!BotValidChatPosition(bs)) return qfalse;
  760.     //
  761.     if (BotVisibleEnemies(bs)) return qfalse;
  762.     //
  763.     BotEntityInfo(bs->enemy, &entinfo);
  764.     if (EntityIsShooting(&entinfo)) return qfalse;
  765.     //
  766.     ClientName(lasthurt_client, name, sizeof(name));
  767.     weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
  768.     //
  769.     BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
  770.     bs->lastchat_time = trap_AAS_Time();
  771.     bs->chatto = CHAT_ALL;
  772.     return qtrue;
  773. }
  774.  
  775. /*
  776. ==================
  777. BotChat_HitNoKill
  778. ==================
  779. */
  780. int BotChat_HitNoKill(bot_state_t *bs) {
  781.     char name[32], *weap;
  782.     float rnd;
  783.     aas_entityinfo_t entinfo;
  784.  
  785.     if (bot_nochat.integer) return qfalse;
  786.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  787.     if (BotNumActivePlayers() <= 1) return qfalse;
  788.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
  789.     //don't chat in teamplay
  790.     if (TeamPlayIsOn()) return qfalse;
  791.     //if fast chat is off
  792.     if (!bot_fastchat.integer) {
  793.         if (random() > rnd * 0.5) return qfalse;
  794.     }
  795.     if (!BotValidChatPosition(bs)) return qfalse;
  796.     //
  797.     if (BotVisibleEnemies(bs)) return qfalse;
  798.     //
  799.     BotEntityInfo(bs->enemy, &entinfo);
  800.     if (EntityIsShooting(&entinfo)) return qfalse;
  801.     //
  802.     ClientName(bs->enemy, name, sizeof(name));
  803.     weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
  804.     //
  805.     BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
  806.     bs->lastchat_time = trap_AAS_Time();
  807.     bs->chatto = CHAT_ALL;
  808.     return qtrue;
  809. }
  810.  
  811. /*
  812. ==================
  813. BotChat_Random
  814. ==================
  815. */
  816. int BotChat_Random(bot_state_t *bs) {
  817.     float rnd;
  818.     char name[32];
  819.  
  820.     if (bot_nochat.integer) return qfalse;
  821.     if (BotIsObserver(bs)) return qfalse;
  822.     if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse;
  823.     //don't chat in teamplay
  824.     if (TeamPlayIsOn()) return qfalse;
  825.     //don't chat when doing something important :)
  826.     if (bs->ltgtype == LTG_TEAMHELP ||
  827.         bs->ltgtype == LTG_TEAMACCOMPANY ||
  828.         bs->ltgtype == LTG_RUSHBASE) return qfalse;
  829.     //
  830.     rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
  831.     if (random() > bs->thinktime * 0.1) return qfalse;
  832.     if (!bot_fastchat.integer) {
  833.         if (random() > rnd) return qfalse;
  834.         if (random() > 0.25) return qfalse;
  835.     }
  836.     if (BotNumActivePlayers() <= 1) return qfalse;
  837.     if (!BotValidChatPosition(bs)) return qfalse;
  838.     //
  839.     if (bs->lastkilledplayer == bs->client) {
  840.         strcpy(name, BotRandomOpponentName(bs));
  841.     }
  842.     else {
  843.         EasyClientName(bs->lastkilledplayer, name, sizeof(name));
  844.     }
  845.     //
  846.     if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
  847.         BotAI_BotInitialChat(bs, "random_misc",
  848.                     BotRandomOpponentName(bs),    // 0
  849.                     name,                        // 1
  850.                     "[invalid var]",            // 2
  851.                     "[invalid var]",            // 3
  852.                     BotMapTitle(),                // 4
  853.                     BotRandomWeaponName(),        // 5
  854.                     NULL);
  855.     }
  856.     else {
  857.         BotAI_BotInitialChat(bs, "random_insult",
  858.                     BotRandomOpponentName(bs),    // 0
  859.                     name,                        // 1
  860.                     "[invalid var]",            // 2
  861.                     "[invalid var]",            // 3
  862.                     BotMapTitle(),                // 4
  863.                     BotRandomWeaponName(),        // 5
  864.                     NULL);
  865.     }
  866.     bs->lastchat_time = trap_AAS_Time();
  867.     bs->chatto = CHAT_ALL;
  868.     return qtrue;
  869. }
  870.  
  871. /*
  872. ==================
  873. BotChatTime
  874. ==================
  875. */
  876. float BotChatTime(bot_state_t *bs) {
  877.     int cpm;
  878.  
  879.     cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
  880.  
  881.     return 2.0;    //(float) trap_BotChatLength(bs->cs) * 30 / cpm;
  882. }
  883.  
  884. /*
  885. ==================
  886. BotChatTest
  887. ==================
  888. */
  889. void BotChatTest(bot_state_t *bs) {
  890.  
  891.     char name[32];
  892.     char *weap;
  893.     int num, i;
  894.  
  895.     num = trap_BotNumInitialChats(bs->cs, "game_enter");
  896.     for (i = 0; i < num; i++)
  897.     {
  898.         BotAI_BotInitialChat(bs, "game_enter",
  899.                     EasyClientName(bs->client, name, 32),    // 0
  900.                     BotRandomOpponentName(bs),                // 1
  901.                     "[invalid var]",                        // 2
  902.                     "[invalid var]",                        // 3
  903.                     BotMapTitle(),                            // 4
  904.                     NULL);
  905.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  906.     }
  907.     num = trap_BotNumInitialChats(bs->cs, "game_exit");
  908.     for (i = 0; i < num; i++)
  909.     {
  910.         BotAI_BotInitialChat(bs, "game_exit",
  911.                     EasyClientName(bs->client, name, 32),    // 0
  912.                     BotRandomOpponentName(bs),                // 1
  913.                     "[invalid var]",                        // 2
  914.                     "[invalid var]",                        // 3
  915.                     BotMapTitle(),                            // 4
  916.                     NULL);
  917.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  918.     }
  919.     num = trap_BotNumInitialChats(bs->cs, "level_start");
  920.     for (i = 0; i < num; i++)
  921.     {
  922.         BotAI_BotInitialChat(bs, "level_start",
  923.                     EasyClientName(bs->client, name, 32),    // 0
  924.                     NULL);
  925.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  926.     }
  927.     num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
  928.     for (i = 0; i < num; i++)
  929.     {
  930.         BotAI_BotInitialChat(bs, "level_end_victory",
  931.                 EasyClientName(bs->client, name, 32),    // 0
  932.                 BotRandomOpponentName(bs),                // 1
  933.                 BotFirstClientInRankings(),                // 2
  934.                 BotLastClientInRankings(),                // 3
  935.                 BotMapTitle(),                            // 4
  936.                 NULL);
  937.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  938.     }
  939.     num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
  940.     for (i = 0; i < num; i++)
  941.     {
  942.         BotAI_BotInitialChat(bs, "level_end_lose",
  943.                 EasyClientName(bs->client, name, 32),    // 0
  944.                 BotRandomOpponentName(bs),                // 1
  945.                 BotFirstClientInRankings(),                // 2
  946.                 BotLastClientInRankings(),                // 3
  947.                 BotMapTitle(),                            // 4
  948.                 NULL);
  949.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  950.     }
  951.     num = trap_BotNumInitialChats(bs->cs, "level_end");
  952.     for (i = 0; i < num; i++)
  953.     {
  954.         BotAI_BotInitialChat(bs, "level_end",
  955.                 EasyClientName(bs->client, name, 32),    // 0
  956.                 BotRandomOpponentName(bs),                // 1
  957.                 BotFirstClientInRankings(),                // 2
  958.                 BotLastClientInRankings(),                // 3
  959.                 BotMapTitle(),                            // 4
  960.                 NULL);
  961.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  962.     }
  963.     EasyClientName(bs->lastkilledby, name, sizeof(name));
  964.     num = trap_BotNumInitialChats(bs->cs, "death_drown");
  965.     for (i = 0; i < num; i++)
  966.     {
  967.         //
  968.         BotAI_BotInitialChat(bs, "death_drown", name, NULL);
  969.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  970.     }
  971.     num = trap_BotNumInitialChats(bs->cs, "death_slime");
  972.     for (i = 0; i < num; i++)
  973.     {
  974.         BotAI_BotInitialChat(bs, "death_slime", name, NULL);
  975.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  976.     }
  977.     num = trap_BotNumInitialChats(bs->cs, "death_lava");
  978.     for (i = 0; i < num; i++)
  979.     {
  980.         BotAI_BotInitialChat(bs, "death_lava", name, NULL);
  981.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  982.     }
  983.     num = trap_BotNumInitialChats(bs->cs, "death_cratered");
  984.     for (i = 0; i < num; i++)
  985.     {
  986.         BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
  987.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  988.     }
  989.     num = trap_BotNumInitialChats(bs->cs, "death_suicide");
  990.     for (i = 0; i < num; i++)
  991.     {
  992.         BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
  993.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  994.     }
  995.     num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
  996.     for (i = 0; i < num; i++)
  997.     {
  998.         BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
  999.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1000.     }
  1001.     num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
  1002.     for (i = 0; i < num; i++)
  1003.     {
  1004.         BotAI_BotInitialChat(bs, "death_gauntlet",
  1005.                 name,                                                // 0
  1006.                 BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  1007.                 NULL);
  1008.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1009.     }
  1010.     num = trap_BotNumInitialChats(bs->cs, "death_rail");
  1011.     for (i = 0; i < num; i++)
  1012.     {
  1013.         BotAI_BotInitialChat(bs, "death_rail",
  1014.                 name,                                                // 0
  1015.                 BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  1016.                 NULL);
  1017.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1018.     }
  1019.     num = trap_BotNumInitialChats(bs->cs, "death_bfg");
  1020.     for (i = 0; i < num; i++)
  1021.     {
  1022.         BotAI_BotInitialChat(bs, "death_bfg",
  1023.                 name,                                                // 0
  1024.                 BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  1025.                 NULL);
  1026.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1027.     }
  1028.     num = trap_BotNumInitialChats(bs->cs, "death_insult");
  1029.     for (i = 0; i < num; i++)
  1030.     {
  1031.         BotAI_BotInitialChat(bs, "death_insult",
  1032.                     name,                                                // 0
  1033.                     BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  1034.                     NULL);
  1035.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1036.     }
  1037.     num = trap_BotNumInitialChats(bs->cs, "death_praise");
  1038.     for (i = 0; i < num; i++)
  1039.     {
  1040.         BotAI_BotInitialChat(bs, "death_praise",
  1041.                     name,                                                // 0
  1042.                     BotWeaponNameForMeansOfDeath(bs->botdeathtype),        // 1
  1043.                     NULL);
  1044.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1045.     }
  1046.     //
  1047.     EasyClientName(bs->lastkilledplayer, name, 32);
  1048.     //
  1049.     num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet");
  1050.     for (i = 0; i < num; i++)
  1051.     {
  1052.         //
  1053.         BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
  1054.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1055.     }
  1056.     num = trap_BotNumInitialChats(bs->cs, "kill_rail");
  1057.     for (i = 0; i < num; i++)
  1058.     {
  1059.         BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
  1060.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1061.     }
  1062.     num = trap_BotNumInitialChats(bs->cs, "kill_telefrag");
  1063.     for (i = 0; i < num; i++)
  1064.     {
  1065.         BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
  1066.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1067.     }
  1068.     num = trap_BotNumInitialChats(bs->cs, "kill_insult");
  1069.     for (i = 0; i < num; i++)
  1070.     {
  1071.         BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
  1072.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1073.     }
  1074.     num = trap_BotNumInitialChats(bs->cs, "kill_praise");
  1075.     for (i = 0; i < num; i++)
  1076.     {
  1077.         BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
  1078.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1079.     }
  1080.     num = trap_BotNumInitialChats(bs->cs, "enemy_suicide");
  1081.     for (i = 0; i < num; i++)
  1082.     {
  1083.         BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
  1084.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1085.     }
  1086.     ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
  1087.     weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
  1088.     num = trap_BotNumInitialChats(bs->cs, "hit_talking");
  1089.     for (i = 0; i < num; i++)
  1090.     {
  1091.         BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
  1092.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1093.     }
  1094.     num = trap_BotNumInitialChats(bs->cs, "hit_nodeath");
  1095.     for (i = 0; i < num; i++)
  1096.     {
  1097.         BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
  1098.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1099.     }
  1100.     num = trap_BotNumInitialChats(bs->cs, "hit_nokill");
  1101.     for (i = 0; i < num; i++)
  1102.     {
  1103.         BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
  1104.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1105.     }
  1106.     //
  1107.     if (bs->lastkilledplayer == bs->client) {
  1108.         strcpy(name, BotRandomOpponentName(bs));
  1109.     }
  1110.     else {
  1111.         EasyClientName(bs->lastkilledplayer, name, sizeof(name));
  1112.     }
  1113.     //
  1114.     num = trap_BotNumInitialChats(bs->cs, "random_misc");
  1115.     for (i = 0; i < num; i++)
  1116.     {
  1117.         //
  1118.         BotAI_BotInitialChat(bs, "random_misc",
  1119.                     BotRandomOpponentName(bs),    // 0
  1120.                     name,                        // 1
  1121.                     "[invalid var]",            // 2
  1122.                     "[invalid var]",            // 3
  1123.                     BotMapTitle(),                // 4
  1124.                     BotRandomWeaponName(),        // 5
  1125.                     NULL);
  1126.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1127.     }
  1128.     num = trap_BotNumInitialChats(bs->cs, "random_insult");
  1129.     for (i = 0; i < num; i++)
  1130.     {
  1131.         BotAI_BotInitialChat(bs, "random_insult",
  1132.                     BotRandomOpponentName(bs),    // 0
  1133.                     name,                        // 1
  1134.                     "[invalid var]",            // 2
  1135.                     "[invalid var]",            // 3
  1136.                     BotMapTitle(),                // 4
  1137.                     BotRandomWeaponName(),        // 5
  1138.                     NULL);
  1139.         trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1140.     }
  1141. }
  1142.